package com.tengju.bff.interfaces.manage.crm.activity.facade.assembler;

import com.tengju.bff.interfaces.manage.crm.activity.form.ActivityTargetSaveForm;
import com.tengju.bff.interfaces.manage.crm.activity.vo.ActivityDetailResVO;
import com.tengju.bff.interfaces.manage.crm.activity.vo.ActivityDetailVO;
import com.tengju.bff.interfaces.shared.DateTimeAssembler;
import com.tengju.bff.interfaces.shared.InterfaceException;
import com.tengju.motivation.domain.model.activity.*;
import com.tengju.motivation.domain.model.goods.Goods;
import com.tengju.motivation.domain.model.goods.GoodsType;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.tengju.bff.interfaces.shared.InterfaceCode.DATA_ILLEGAL;
import static com.tengju.bff.interfaces.shared.InterfaceCode.PARAM_ERROR;
import static com.tengju.motivation.domain.model.activity.ActivityType.SALE;

public class ActivityAssembler {

    private ActivityAssembler() {
    }

    public static ActivityDetailResVO assemblerToVO(Activity activity) {
        if (activity.getActivityId() == null | activity.getExtraInfo() == null) {
            return null;
        }
        if (activity.getStartTime() != null && activity.getEndTime() != null && activity.getEndTime().isAfter(activity.getStartTime())) {
            long continueDays = activity.getEndTime().toLocalDate().toEpochDay() - activity.getStartTime().toLocalDate().toEpochDay() + 1;
            return new ActivityDetailResVO(activity.getActivityId().getValue(),
                    activity.getName(),
                    activity.getStartTime().toLocalDate(),
                    activity.getEndTime().toLocalDate(),
                    continueDays,
                    activity.getExtraInfo().getActivityType().getVal());
        }
        return null;
    }


    public static ActivityDetailVO toDetail(Activity activity, List<ActivityTarget> targets,
                                            Map<String, Goods> goodsMap, Map<String, Goods> keyBrandsMap) {
        if (activity == null || activity.getExtraInfo() == null) {
            return null;
        }

        ActivityDetailVO detailVO;
        Activity.ActivityExtraInfo extra = activity.getExtraInfo();

        ActivityDetailVO.ActivityDetailVOBuilder detailVOBuilder = ActivityDetailVO.builder()
                .activityName(activity.getName())
                .activityTime(DateTimeAssembler.formatDateTillSecond(activity.getStartTime())
                        + " 到 "
                        + DateTimeAssembler.formatDateTillSecond(activity.getEndTime()))
                .activityType(Optional.ofNullable(extra.getActivityType())
                        .map(ActivityType::getDesc)
                        .orElse("-")
                )
                .customerType(Optional.ofNullable(extra.getUserType())
                        .map(ActivityUserType::getDesc)
                        .orElse("-")
                )
                .activityTarget(Optional.of(extra)
                        .map(Activity.ActivityExtraInfo::getTargetType)
                        .map(type -> {
                            if (type == ActivityTargetType.SALE) {
                                return type.getDesc();
                            } else if (type == ActivityTargetType.GROWTH) {
                                return String.format("%s(%s)",
                                        extra.getTargetGrownUserLevel().getDesc(),
                                        Activity.LIMIT_GROW_TYPE.getDesc());
                            } else {
                                return null;
                            }
                        })
                        .orElse("-"))
                .warmupTime(Optional.ofNullable(extra.getWarmStartTime())
                        .map(DateTimeAssembler::formatDateTillSecond)
                        .orElse(""))
                .freezeTime(Optional.ofNullable(extra.getFreezeStartTime())
                        .map(DateTimeAssembler::formatDateTillSecond)
                        .orElse(""));
        detailVO = detailVOBuilder.build();
        if (activity.getExtraInfo().getActivityType() == SALE) {
            fillGoodsInfo(activity, detailVO);
        }
        ActivityTargetSet allTargets = fillEmptyTargets(activity, targets, goodsMap, keyBrandsMap);
        fillTarget(detailVO, activity, allTargets, goodsMap, keyBrandsMap);
        return detailVO;
    }


    private static void fillGoodsInfo(Activity activity, ActivityDetailVO detailVO) {
        if (activity == null || detailVO == null || activity.getExtraInfo() == null) {
            return;
        }

        Activity.ActivityExtraInfo extra = activity.getExtraInfo();
        if (extra.getTargetType() == ActivityTargetType.SALE) {

            detailVO.setLimitCustomer(new ActivityDetailVO.LimitCustomer(
                    "VTN等级",
                    extra.getLimitCustomerLevelNames()
            ));
            if (extra.getLimitGoods() != null) {
                String limitGoodsType = Optional.ofNullable(extra.getLimitGoods().getLimitGoodsType())
                        .map(GoodsType::getDesc)
                        .orElse("");
                detailVO.setLimitGoods(new ActivityDetailVO.LimitGoods(limitGoodsType,
                                Optional.of(extra.getLimitGoods().getLimitSolution())
                                        .filter(s -> s != LimitSolution.NONE)
                                        .map(s -> String.format("指定%s%s", limitGoodsType, s.getDesc()))
                                        .orElse("所有品牌参与"),
                                Optional.ofNullable(extra.getLimitGoods().getGoodsList())
                                        .map(goods -> goods.stream()
                                                .map(g -> new ActivityDetailVO.Goods(g.getId(), g.getName()))
                                                .collect(Collectors.toList()))
                                        .orElse(null)
                        )
                );
            }
        }
    }

    private static ActivityTargetSet fillEmptyTargets(Activity activity, List<ActivityTarget> targets,
                                                      Map<String, Goods> goodsMap,
                                                      Map<String, Goods> keyBrandsMap) {
        LocalDateTime startDate = activity.getStartTime();
        LocalDateTime endDate = activity.getEndTime();
        ActivityTargetSet targetSet = new ActivityTargetSet(activity.getActivityId(),
                Optional.ofNullable(targets)
                        .map(list -> list.stream()
                                //过滤非活动时间目标
                                .filter(t -> t.isInProgress(startDate, endDate))
                                .collect(Collectors.toList())
                        ).orElse(new ArrayList<>())
        );
        Activity.ActivityExtraInfo extra = activity.getExtraInfo();
        ActivityTargetType targetType = extra.getTargetType();
        Stream.iterate(startDate, d -> d.plusDays(1))
                .limit(activity.lastDuration())
                .forEach(date -> {
                    if (activity.isSale() && extra.getLimitGoods() != null) {
                        LimitSolution limitSolution = extra.getLimitGoods().getLimitSolution();
                        final Collection<Goods> goodsList = limitSolution == LimitSolution.INCLUDE ?
                                goodsMap.values() : keyBrandsMap.values();
                        goodsList.forEach(goods -> {
                            if (targetSet.contains(activity.getActivityId(), goods.getLongId(), date.toLocalDate())) {
                                return;
                            }
                            targetSet.add(new ActivityTarget(
                                    null,
                                    activity.getActivityId(),
                                    date,
                                    goods.getName(),
                                    0L,
                                    targetType,
                                    goods.getGoodsType(),
                                    Long.parseLong(goods.getId()),
                                    null,
                                    null,
                                    null,
                                    null
                            ));
                        });
                    } else {
                        UserLevel targetLevel = extra.getTargetGrownUserLevel();
                        if (targetLevel == null) {
                            throw new InterfaceException(DATA_ILLEGAL, "招聘活动" + activity.getActivityId() + "没有目标等级");
                        }
                        if (targetSet.contains(activity.getActivityId(), targetLevel.getVal(), date.toLocalDate())) {
                            return;
                        }
                        targetSet.add(new ActivityTarget(
                                null,
                                activity.getActivityId(),
                                date,
                                Optional.of(targetLevel)
                                        .map(UserLevel::getDesc)
                                        .orElse("未知"),
                                0L,
                                targetType,
                                GoodsType.PACKAGE,
                                targetLevel.getVal(),
                                null,
                                null,
                                null,
                                null
                        ));
                    }
                });
        return targetSet;
    }

    private static void fillTarget(ActivityDetailVO detailVO, Activity activity,
                                   ActivityTargetSet targets, Map<String, Goods> goodsMap,
                                   Map<String, Goods> keyBrandMap) {
        if (!targets.isEmpty()) {
            Long targetTotalAmount = 0L;
            List<ActivityDetailVO.LimitRule> limitRules = new ArrayList<>();
            Activity.ActivityExtraInfo extra = activity.getExtraInfo();
            Map<Long/* subjectId*/, List<ActivityDetailVO.Goods>> referGoodsMap = new HashMap<>();
            for (ActivityTarget target : targets.getTargets()) {
                Long subjectId = target.getTargetSubjectId();//销售活动：商品id，招募活动：等级id（大数据枚举）
                List<ActivityDetailVO.Goods> referGoods = referGoodsMap.get(subjectId);
                if (referGoods == null) {
                    referGoods = Optional.ofNullable(target.getTargetCompareSubjects())
                            .map(goods -> goods.stream()
                                    .map(g -> new ActivityDetailVO.Goods(g.getId(), g.getName()))
                                    .collect(Collectors.toList()))
                            .orElse(null);
                    referGoodsMap.put(subjectId, referGoods);
                }
            }

            for (ActivityTarget target : targets.getTargets()) {
                targetTotalAmount += target.getTargetValue();
                Long subjectId = target.getTargetSubjectId();//销售活动：商品id，招募活动：等级id（大数据枚举）
                String ruleType;
                if (extra.getActivityType() == SALE) {
                    ruleType = Optional.of(subjectId)
                            .map(String::valueOf)
                            .map(id -> {
                                Goods good = goodsMap.get(id);
                                return good == null ? keyBrandMap.get(id) : good;
                            })
                            .map(Goods::getName)
                            .orElse("未知");
                } else {
                    ruleType = Optional.ofNullable(extra.getTargetGrownUserLevel())
                            .map(UserLevel::getDesc)
                            .orElse(null);
                }

                limitRules.add(ActivityDetailVO.LimitRule.builder()
                        .ruleId(Optional.ofNullable(target.getTargetId())
                                .map(TargetId::toString)
                                .orElse(null))
                        .ruleSubjectId(subjectId.toString())
                        .ruleType(ruleType)
                        .targetType(extra.getTargetType().getDesc())
                        .date(DateTimeAssembler.formatDateTillDay(target.getActivityTime()))
                        .targetAmount(String.valueOf(target.getTargetValue()))
                        .referStartDate(DateTimeAssembler.formatDateTillDay(target.getTargetReferStartTime()))
                        .referEndDate(DateTimeAssembler.formatDateTillDay(target.getTargetReferEndTime()))
                        .referGoods(referGoodsMap.get(subjectId))
                        .build()
                );
            }
            for (ActivityDetailVO.LimitRule rule : limitRules) {
                rule.setTargetTotalAmount(String.valueOf(targetTotalAmount));
            }
            detailVO.setLimitRules(limitRules);
        }
    }

    public static List<ActivityTarget> formToDomain(Activity activity, ActivityTargetSaveForm form) {
        List<ActivityTarget> targets = new ArrayList<>();
        ActivityTargetType targetType = activity.getExtraInfo().getTargetType();
        AtomicReference<Long> total = new AtomicReference<>(0L);
        form.getLimitRules().forEach(limitRule -> {
            Long amount = Optional.ofNullable(limitRule.getTargetAmount())
                    .map(Long::parseLong)
                    .orElse(0L);
            total.updateAndGet(v -> v + amount);
            GoodsType subjectType = activity.isSale() ?
                    activity.getExtraInfo().getLimitGoods().getLimitGoodsType() : GoodsType.PACKAGE;
            targets.add(new ActivityTarget(
                    Optional.ofNullable(limitRule.getRuleId())
                            .map(Long::parseLong)
                            .map(TargetId::new)
                            .orElse(null),
                    activity.getActivityId(),
                    DateTimeAssembler.parseDateTillDay(limitRule.getDate()),
                    limitRule.getRuleType(),
                    amount,
                    targetType,
                    subjectType,
                    Long.parseLong(limitRule.getRuleSubjectId()),
                    DateTimeAssembler.parseDateTillDay(limitRule.getReferStartDate()),
                    DateTimeAssembler.parseDateTillDay(limitRule.getReferEndDate()),
                    subjectType,
                    Optional.ofNullable(limitRule.getReferGoods())
                            .map(goods -> goods.stream()
                                    .map(good -> new Goods(subjectType, good.getId(), good.getName()))
                                    .collect(Collectors.toList()))
                            .orElse(new ArrayList<>())
            ));
        });
        Optional.ofNullable(form.getLimitRules())
                .map(list -> list.get(0))
                .map(ActivityDetailVO.LimitRule::getTargetTotalAmount)
                .map(Long::parseLong)
                .filter(t -> t.equals(total.get()))
                .orElseThrow(() -> new InterfaceException(PARAM_ERROR, "总目标未被完全拆解"));
        return targets;
    }

}
